package com.xuecheng.order.job;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.result.BaseWxPayResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.service.WxPayService;
import com.xuecheng.api.order.model.dto.OrdersDTO;
import com.xuecheng.api.order.model.dto.PayResultModel;
import com.xuecheng.order.convert.OrdersConvert;
import com.xuecheng.order.entity.Orders;
import com.xuecheng.order.entity.Pay;
import com.xuecheng.order.mapper.OrdersMapper;
import com.xuecheng.order.service.OrdersService;
import com.xuecheng.order.service.PayService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created on 2021/04/22/2:03 周四
 *
 * @author Lantin
 */

@Component
@Slf4j
public class CheckPaymentJob {

    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private PayService payService;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private OrdersService ordersService;

    @Value("${rocketmq.massage.topic}")
    private String topic;

    @Autowired
    private WxPayService wxPayService;

    /**
     * 1、30秒一次向微信查询10分钟内的所有未支付订单的支付结果
     */
    @XxlJob("payHandle")
    public void checkPaymentJobHandler() throws Exception {
        XxlJobHelper.log("XXL-JOB, 订单支付回查微信");

        log.info("定时任务==>回查微信支付结果，start at :" + LocalDateTime.now());
        // default success
        //扫描数据库支付订单情况
        List<Orders> ordersList = ordersMapper.selectUnpaidOrders();
        //查询结果不为空，则回查未支付订单的消息
        if (CollectionUtils.isEmpty(ordersList)) {
            XxlJobHelper.handleFail("无未支付订单，time=" + LocalDateTime.now());
            log.info("无未支付订单，time=" + LocalDateTime.now());
            return;
        }

        //提取出Order的所有订单id
        List<Long> orderIdList = ordersList.stream().map(Orders::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Pay> payWrapper = Wrappers.lambdaQuery(Pay.class)
                .eq(Pay::getStatus, Pay.PAY_STATUS_UNPAID)
                .in(Pay::getOrderId, orderIdList);
        List<Pay> pays = payService.getBaseMapper().selectList(payWrapper);
        if (CollectionUtils.isEmpty(pays)) {
            XxlJobHelper.handleFail("无未支付的订单支付信息，time=" + LocalDateTime.now());
            log.info("无未支付的订单支付信息，time=" + LocalDateTime.now());
            return;
        }

        //遍历所有订单支付详情 发送请求 向查询微信此订单的支付情况
        for (Pay pay : pays) {
            String payNumber = pay.getPayNumber();
            String outTradeNo = "";
            for (Orders order : ordersList) {
                if (pay.getOrderId().equals(order.getId())) {
                    outTradeNo = order.getOrderNo();
                    break;
                }
            }
            log.info("开始向微信查询订单状态，微信支付单号：{}，商户订单号：{}", pay.getPayNumber(), outTradeNo);
            WxPayOrderQueryResult result = wxPayService.queryOrder(payNumber, outTradeNo);
            String returnCode = result.getReturnCode();
            if (!Pay.PAY_RESPONSE_STATUS_SUCCESS.equals(returnCode)) {
                log.info("查询失败，等待下次重试，异常为：{}", result.getReturnMsg());
            }
            String resultCode = result.getResultCode();
            if (!Pay.PAY_RESPONSE_STATUS_SUCCESS.equals(resultCode)) {
                log.info("查询失败，系统异常：{}，商户订单号:{}", result.getErrCodeDes(), result.getOutTradeNo());
            }
            String tradeState = result.getTradeState();
            if (!Pay.PAY_RESPONSE_STATUS_SUCCESS.equals(tradeState)) {
                log.info("用户支付状态异常,订单号:{},交易结果:{}",
                        result.getOutTradeNo(),
                        tradeState);
            }
            Orders orders = ordersService.getById(pay.getOrderId());
            LocalTransactionState state = this.sendPaymentTxMsg(result, resultCode, orders, pay);
            if (state != LocalTransactionState.COMMIT_MESSAGE) {
                log.info("发送支付结果事务消息失败");
            }
        }
    }

    /**
     * 1、一天一次 每天凌晨1点 向微信查询所有未支付订单的支付结果
     */
    @XxlJob("payHandleOnceADay")
    public void checkPaymentJobHandlerOnceADay() throws Exception {
        XxlJobHelper.log("XXL-JOB, 订单支付回查微信");

        log.info("定时任务==>回查微信支付结果，start at :" + LocalDateTime.now());
        // default success
        //扫描数据库支付订单情况
        List<Orders> ordersList = ordersMapper.selectAllOrders();
        //查询结果不为空，则回查未支付订单的消息
        if (CollectionUtils.isEmpty(ordersList)) {
            XxlJobHelper.handleFail("无未支付订单，time=" + LocalDateTime.now());
            log.info("无未支付订单，time=" + LocalDateTime.now());
            return;
        }
        //提取出Order的所有订单id
        List<Long> orderIdList = ordersList.stream().map(Orders::getId).collect(Collectors.toList());
        LambdaQueryWrapper<Pay> payWrapper = Wrappers.lambdaQuery(Pay.class)
                .eq(Pay::getStatus, Pay.PAY_STATUS_UNPAID)
                .in(Pay::getOrderId, orderIdList);
        List<Pay> pays = payService.getBaseMapper().selectList(payWrapper);
        if (CollectionUtils.isEmpty(pays)) {
            XxlJobHelper.handleFail("无未支付的订单支付信息，time=" + LocalDateTime.now());
            log.info("无未支付的订单支付信息，time=" + LocalDateTime.now());
            return;
        }

        for (Pay pay : pays) {
            String payNumber = pay.getPayNumber();
            WxPayOrderQueryResult result = wxPayService.queryOrder(payNumber, null);
            String returnCode = result.getReturnCode();
            if (!Pay.PAY_RESPONSE_STATUS_SUCCESS.equals(returnCode)) {
                log.info("查询失败，等待下次重试，异常为：{}", result.getReturnMsg());
            }
            String resultCode = result.getResultCode();
            if (!Pay.PAY_RESPONSE_STATUS_SUCCESS.equals(resultCode)) {
                log.info("查询失败，系统异常：{}，商户订单号:{}", result.getErrCodeDes(), result.getOutTradeNo());
            }
            String tradeState = result.getTradeState();
            if (!Pay.PAY_RESPONSE_STATUS_SUCCESS.equals(tradeState)) {
                log.info("用户支付状态异常,订单号:{},交易结果:{}",
                        result.getOutTradeNo(),
                        tradeState);
            }
            Orders orders = ordersService.getById(pay.getOrderId());
            LocalTransactionState state = this.sendPaymentTxMsg(result, resultCode, orders, pay);
            if (state != LocalTransactionState.COMMIT_MESSAGE) {
                log.info("发送支付结果事务消息失败");
            }
        }
    }


    private LocalTransactionState sendPaymentTxMsg(WxPayOrderQueryResult result, String resultCode, Orders order, Pay orderPay) {
        //发送事务消息，封装交易结果信息
        PayResultModel model = new PayResultModel();
        OrdersDTO ordersDTO = OrdersConvert.INSTANCE.ordersToDTO(order);
        model.setOrder(ordersDTO);
        model.setPayMethod(orderPay.getPayMethod());
        String timeEnd = result.getTimeEnd();
        //设置支付时间
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        LocalDateTime payDate = LocalDateTime.parse(timeEnd, timeFormatter);
        model.setPayDate(payDate);
        model.setPayNumber(result.getTransactionId());
        model.setTradeStatus(resultCode);
        //订单应结金额
        Integer settlementTotalFee = result.getSettlementTotalFee();
        if (!ObjectUtils.isEmpty(settlementTotalFee)) {
            String yuan = BaseWxPayResult.fenToYuan(settlementTotalFee);
            model.setReceiptAmount(new BigDecimal(yuan));
        }
        //用户实付金额
        String realPayment = BaseWxPayResult.fenToYuan(result.getCashFee());
        model.setBuyerPayAmount(new BigDecimal(realPayment));
        model.setPayResponse(result.getXmlString());

        String jsonString = JSON.toJSONString(model);
        //发送事务消息
        log.info("发送事务消息，订单号：{}", model.getOrder().getOrderNo());
        Message<String> message = MessageBuilder.withPayload(jsonString).build();
        //判断mq消息发送结果状态
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(topic, message, null);
        return sendResult.getLocalTransactionState();
    }
}
